home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xarchie-2.0.9 / dirsend.c < prev    next >
C/C++ Source or Header  |  1995-06-18  |  34KB  |  1,239 lines

  1. /*
  2.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  3.  *
  4.  * For copying and distribution information, please see the file
  5.  * <copyright.h>.
  6.  *
  7.  * xarchie v2.0 - (gf)     - Sync with archie-1.4.1 (uses config.h)
  8.  * v1.2.3 - 11/04/91 (bcn) - removed host comparison and replaced with check
  9.                   for connection id (undoes effect of v1.2.2.).
  10.  * v1.2.2 - 11/02/91 (gf)  - removed extra inet_ntoa() calls and stuff for
  11.                  multi-interface nets (lmjm@doc.imperial.ac.uk)
  12.  * v1.2.1 - 10/20/91 (gf)  - asynch implementation
  13.  * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  14.  * v1.1.2 - 08/30/91 (bpk) - added VMS support
  15.  * v1.1.1 - 08/29/91 (bcn) - changed backoff handling
  16.  * v1.1.0 - 08/13/91 (gf)  - added XArchie status calls
  17.  *
  18.  * gf: 20 Oct 1991:
  19.  *  Broken into pieces so that under X dirsend() doesn't block in select()
  20.  *  but rather uses Xt calls to allow continued event processing. If
  21.  *  XARCHIE is not defined, can still be used since processEvent() will
  22.  *  use select() in this case.
  23.  *
  24.  * bpk: For archie client v1.3.2:
  25.  * If you're going to hack on this, I'd suggest using unifdef with -UCUTCP
  26.  * and possibly -UVMS, for your working copy.  When you've got your changes
  27.  * done, come back and add them into this main file.  It's getting pretty
  28.  * nasty down there.
  29.  */
  30.  
  31. #include <copyright.h>
  32. #include <stdio.h>
  33. #include <errno.h>
  34.  
  35. /*
  36.  * Complaints or suggestions regarding the portability or lack thereof
  37.  * of these includes and defines should be directed to Brendan Kehoe,
  38.  * brendan@cs.widener.edu.
  39.  */
  40. #ifdef VMS
  41. # ifdef WOLLONGONG
  42. #  include "twg$tcp:[netdist.include]netdb.h"
  43. # else /* not Wollongong */
  44. #  ifdef UCX
  45. #   include <netdb.h>
  46. #  else /* Multinet */
  47. #   include "multinet_root:[multinet.include]netdb.h"
  48. #  endif
  49. # endif
  50. # include <vms.h>
  51. #else /* not VMS */
  52. # ifdef PCNFS
  53. #  include <tklib.h>
  54. #  include <tk_errno.h>
  55. #  include <sys/nfs_time.h>
  56. # endif
  57. # include "config.h"                /* gf */
  58. # include "stringdefs.h"            /* gf */
  59. # include "selectdefs.h"            /* gf */
  60. # include <sys/time.h>                /* gf */
  61. # ifdef CUTCP
  62. #  include <msdos/cutcp.h>
  63. #  include <msdos/netevent.h>
  64. #  include <msdos/hostform.h>
  65. # else /* not CUTCP */
  66. #  include <netdb.h>
  67. #  include <sys/socket.h>
  68. # endif
  69. # ifndef IN_H
  70. #  ifndef _TYPES_
  71. #   include <sys/types.h>
  72. #  endif
  73. #  include <netinet/in.h>
  74. #  define IN_H
  75. # endif
  76. # if !defined(hpux) && !defined(PCNFS)
  77. #  include <arpa/inet.h>
  78. # endif
  79. #endif /* !VMS */
  80.  
  81. /* Interactive UNIX keeps some of the socket definitions in funny places.  */
  82. #ifdef ISC
  83. # include <net/errno.h>
  84. #endif /* ISC */
  85. /* PC-NFS Toolkit 4.0 keeps important forward definitions here. */
  86. #ifdef PCNFS
  87. # include <in_addr.h>
  88. #endif
  89.  
  90. #include <pfs.h>
  91. #include <pprot.h>
  92. #include <pcompat.h>
  93. #include <perrno.h>
  94.  
  95. /* gf: Removed SUN_GNU_FIX stuff since inet_ntoa.c is now included. */
  96.  
  97. static int notprived = 0;
  98. #ifndef MSDOS
  99. extern int errno;
  100. #endif
  101. extern int perrno;
  102. #ifdef DEBUG
  103. extern int pfs_debug;
  104. #endif
  105. extern int pfs_disable_flag;
  106.  
  107. char    *nlsindex();
  108.  
  109. #define max(X, Y)  ((X) > (Y) ? (X) : (Y))
  110.  
  111. static int        dir_udp_port = 0;    /* Remote UDP port number */
  112.  
  113. #ifdef CUTCP
  114. # define    NS_TIMEOUT    15
  115. #endif
  116.  
  117. static unsigned short    next_conn_id = 0;
  118.  
  119. /* Always needed externally */
  120. int client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
  121. int client_dirsrv_retry = CLIENT_DIRSRV_RETRY; 
  122. int rdgram_priority = 0;            /* gf: was in rdgram.h */
  123.  
  124. /* These were parameters to dirsend() */
  125. static PTEXT pkt;
  126. static char *hostname;
  127. static struct sockaddr_in *hostaddr;
  128.  
  129. /* These were locals in dirsend(). Note that the initializations here
  130.  * are really meaningless since we have to redo them for each call to
  131.  * dirsend() since they were formerly automatically initialized.
  132.  */
  133. static PTEXT        first = NULL;    /* First returned packet     */
  134. static PTEXT        next;        /* The one we are waiting for      */
  135. static PTEXT        vtmp;           /* For reorganizing linked list  */
  136. static PTEXT        comp_thru;    /* We have all packets though    */
  137. static int        lp = -1;    /* Opened UDP port             */
  138. static int        hdr_len;    /* Header Length                 */
  139. static int        nd_pkts;    /* Number of packets we want     */
  140. static int        no_pkts;    /* Number of packets we have     */
  141. static int        pkt_cid;        /* Packet connection identifier  */
  142. static unsigned short    this_conn_id;    /* Connection ID we are using    */
  143. static unsigned short    recvd_thru;    /* Received through              */
  144. static short        priority;    /* Priority for request          */
  145. static short        one = 0;    /* Pointer to value 1            */
  146. static short        zero = 0;    /* Pointer to value 0         */
  147. static char        *seqtxt;    /* Pointer to text w/ sequence # */
  148. static struct sockaddr_in  us;        /* Our address                   */
  149. static struct sockaddr_in  to;        /* Address to send query     */
  150. static struct sockaddr_in  from;    /* Reply received from         */
  151. static int        from_sz;    /* Size of from structure     */
  152. static struct hostent    *host;        /* Host info from gethostbyname  */
  153. static long        newhostaddr;    /* New host address from *host   */
  154. static int        req_udp_port=0; /* Requested port (optional)     */
  155. static char        *openparen;    /* Delimits port in name         */
  156. static char        hostnoport[500];/* Host name without port        */
  157. static int        ns;        /* Number of bytes actually sent */
  158. static int        nr;        /* Number of bytes received      */
  159. static fd_set    readfds;    /* Used for select         */
  160. static int        tmp;
  161. static char        *ctlptr;    /* Pointer to control field      */
  162. static short        stmp;        /* Temp short for conversions    */
  163. static int        backoff;    /* Server requested backoff      */
  164. static unsigned char    rdflag11;    /* First byte of flags (bit vect)*/
  165. static unsigned char    rdflag12;    /* Second byte of flags (int)    */
  166. static int        scpflag = 0;    /* Set if any sequencd cont pkts */
  167. static int        ackpend = 0;    /* Acknowledgement pending      */
  168. static int        gaps = 0;    /* Gaps present in recvd pkts   */
  169. static struct timeval    timeout;    /* Time to wait for response    */
  170. static struct timeval    ackwait;    /* Time to wait before acking   */
  171. static struct timeval    gapwait;    /* Time to wait b4 filling gaps */
  172. static struct timeval    *selwait;    /* Time to wait for select      */
  173. static int        retries;    /* was = client_dirsrv_retry    */
  174. char   to_hostname[512];        /* lmjm: saves inet_ntoa() str  */
  175.  
  176. /* These are added so dirsend() "blocks" properly */
  177. static PTEXT dirsendReturn;
  178. static int dirsendDone;
  179.  
  180. /* And here are the values for dirsendDone */
  181. #define DSRET_DONE        1
  182. #define DSRET_SEND_ERROR    -1
  183. #define DSRET_RECV_ERROR    -2
  184. #define DSRET_SELECT_ERROR    -3
  185. #define DSRET_TIMEOUT        -4
  186. #define DSRET_ABORTED        -5
  187.  
  188. /* New procedures to break up dirsend() */
  189. static int initDirsend();
  190. static void retryDirsend(), keepWaitingDirsend();
  191. static void timeoutProc();
  192. static void readProc();
  193.  
  194. /* Wrappers around X calls to allow non-X usage */
  195. static void addInputSource(), removeInputSource();
  196. static void addTimeOut(), removeTimeOut();
  197. static void processEvent();
  198.  
  199. /* External status procedures */
  200. extern void status0(),status1(),status2();
  201.  
  202. #if defined(XARCHIE) || defined(VARCHIE)
  203. static int packetCounter;
  204. #endif
  205.  
  206. /* Extra stuff for the asynchronous X version of dirsend() */
  207. #ifdef XARCHIE
  208. #include <X11/Intrinsic.h>
  209. extern XtAppContext appContext;
  210. #else
  211. #ifdef VARCHIE
  212. #include "xtypes.h"
  213. #else
  214. typedef char *XtPointer;
  215. typedef char *XtInputId;
  216. typedef char *XtIntervalId;
  217. #endif /* VARCHIE */
  218. #endif /* XARCHIE */
  219.  
  220. static XtInputId inputId;
  221. static XtIntervalId timerId = (XtIntervalId)0;
  222.  
  223. /*
  224.  * dirsend - send packet and receive response
  225.  *
  226.  *   DIRSEND takes a pointer to a structure of type PTEXT, a hostname,
  227.  *   and a pointer to a host address.  It then sends the supplied
  228.  *   packet off to the directory server on the specified host.  If
  229.  *   hostaddr points to a valid address, that address is used.  Otherwise,
  230.  *   the hostname is looked up to obtain the address.  If hostaddr is a
  231.  *   non-null pointer to a 0 address, then the address will be replaced
  232.  *   with that found in the hostname lookup.
  233.  *
  234.  *   DIRSEND will wait for a response and retry an appropriate
  235.  *   number of times as defined by timeout and retries (both static
  236.  *   variables).  It will collect however many packets form the reply, and
  237.  *   return them in a structure (or structures) of type PTEXT.
  238.  *
  239.  *   DIRSEND will free the packet that it is presented as an argument.
  240.  *   The packet is freed even if dirsend fails.
  241.  */
  242. PTEXT
  243. dirsend(pkt_p,hostname_p,hostaddr_p)
  244.     PTEXT pkt_p;
  245.     char *hostname_p;
  246.     struct sockaddr_in    *hostaddr_p;
  247. {
  248.     /* copy parameters to globals since other routines use them */
  249.     pkt = pkt_p;
  250.     hostname = hostname_p;
  251.     hostaddr = hostaddr_p;
  252.     /* Do the initializations of formerly auto variables */
  253.     first = NULL;
  254.     lp = -1;
  255.     one = 0;
  256.     zero = 0;
  257.     req_udp_port=0;
  258.     scpflag = 0;
  259.     ackpend = 0;
  260.     gaps = 0;
  261.     retries = client_dirsrv_retry;
  262.  
  263.     if (initDirsend() < 0)
  264.     return(NULL);
  265.     addInputSource();
  266.     /* set the first timeout */
  267.     retryDirsend();
  268.  
  269.     dirsendReturn = NULL;
  270.     dirsendDone = 0;
  271.     /* Until one of the callbacks says to return, keep processing events */
  272.     while (!dirsendDone)
  273.     processEvent();
  274.     /* Clean up event generators */
  275.     removeTimeOut();
  276.     removeInputSource();
  277. #if defined(XARCHIE) || defined(VARCHIE)
  278.     /* Set status if needed (has to be outside of loop or X will crash) */
  279.     switch (dirsendDone) {
  280.     case DSRET_SEND_ERROR: status0("Send error"); break;
  281.     case DSRET_RECV_ERROR: status0("Recv error"); break;
  282.         case DSRET_TIMEOUT:
  283.         status1("Connection to %s timed out",to_hostname);
  284.         break;
  285.         case DSRET_ABORTED: status0("Aborted"); break;
  286.     }
  287. #endif
  288.     /* Return whatever we're supposed to */
  289.     return(dirsendReturn);
  290. }
  291.  
  292.  
  293. /*    -    -    -    -    -    -    -    -    */
  294. /* This function does all the initialization that used to be done at the
  295.  * start of dirsend(), including opening the socket descriptor "lp". It
  296.  * returns the descriptor if successful, otherwise -1 to indicate that
  297.  * dirsend() should return NULL immediately.
  298.  */
  299. static int
  300. initDirsend()
  301. {
  302. #if defined(XARCHIE) || defined(VARCHIE)
  303.     status0("Initializing");
  304. #endif
  305.  
  306.     if(one == 0) one = htons((short) 1);
  307.  
  308.     priority = htons(rdgram_priority);
  309.  
  310.     timeout.tv_sec = client_dirsrv_timeout;
  311.     timeout.tv_usec = 0;
  312.  
  313.     ackwait.tv_sec = 0;
  314.     ackwait.tv_usec = 500000;
  315.  
  316.     gapwait.tv_sec = (client_dirsrv_timeout < 5 ? client_dirsrv_timeout : 5);
  317.     gapwait.tv_usec = 0;
  318.  
  319.     comp_thru = NULL;
  320.     perrno = 0;
  321.     nd_pkts = 0;
  322.     no_pkts = 0;
  323.     pkt_cid = 0;
  324.  
  325.     /* Find first connection ID */
  326.     if(next_conn_id == 0) {
  327.     srand(getpid()+time(0)); /* XXX: arg ok, but not right type. */
  328.     next_conn_id = rand();
  329.     }
  330.  
  331.  
  332.     /* If necessary, find out what udp port to send to */
  333.     if (dir_udp_port == 0) {
  334.         register struct servent *sp;
  335.     tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  336. #ifdef USE_ASSIGNED_PORT
  337.     /* UCX needs 0 & -1 */
  338.     sp = getservbyname("prospero","udp");
  339.     if (sp == (struct servent *)0 || sp == (struct servent *)-1) {
  340. #ifdef DEBUG
  341.         if (pfs_debug)
  342.         fprintf(stderr, "dirsrv: udp/prospero unknown service - using %d\n", 
  343.             PROSPERO_PORT);
  344. #endif
  345.         dir_udp_port = htons((u_short) PROSPERO_PORT);
  346.         }
  347. #else
  348.     /* UCX needs 0 & -1 */
  349.     sp = getservbyname("dirsrv","udp");
  350.     if (sp == (struct servent *)0 || sp == (struct servent *)-1) {
  351. #ifdef DEBUG
  352.         if (pfs_debug)
  353.         fprintf(stderr, "dirsrv: udp/dirsrv unknown service - using %d\n", 
  354.             DIRSRV_PORT);
  355. #endif
  356.         dir_udp_port = htons((u_short) DIRSRV_PORT);
  357.         }
  358. #endif
  359.     else dir_udp_port = sp->s_port;
  360.     pfs_enable = tmp;
  361. #ifdef DEBUG
  362.         if (pfs_debug > 3)
  363.             fprintf(stderr,"dir_udp_port is %d\n", ntohs(dir_udp_port));
  364. #endif
  365.     }
  366.  
  367.     /* If we were given the host address, then use it.  Otherwise  */
  368.     /* lookup the hostname.  If we were passed a host address of   */
  369.     /* 0, we must lookup the host name, then replace the old value */
  370.     if(!hostaddr || (hostaddr->sin_addr.s_addr == 0)) {
  371.     /* I we have a null host name, return an error */
  372.     if((hostname == NULL) || (*hostname == '\0')) {
  373. #ifdef DEBUG
  374.             if (pfs_debug)
  375.                 fprintf(stderr, "dirsrv: Null hostname specified\n");
  376. #endif
  377.         perrno = DIRSEND_BAD_HOSTNAME;
  378.         ptlfree(pkt);
  379.             /* return(NULL); */
  380.         return(-1);
  381.     }
  382.     /* If a port is included, save it away */
  383.     if(openparen = index(hostname,'(')) {
  384.         sscanf(openparen+1,"%d",&req_udp_port);
  385.         strncpy(hostnoport,hostname,400);
  386.         if((openparen - hostname) < 400) {
  387.         *(hostnoport + (openparen - hostname)) = '\0';
  388.         hostname = hostnoport;
  389.         }
  390.     }
  391. #if defined(XARCHIE) || defined(VARCHIE)
  392.     status1("Getting address for host \"%s\"",hostname);
  393. #endif
  394.     tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  395.     if((host = gethostbyname(hostname)) == NULL) {
  396.         pfs_enable = tmp;
  397.         /* Check if a numeric address */
  398.         newhostaddr = inet_addr(hostname);
  399.         if(newhostaddr == -1) {
  400. #ifdef DEBUG
  401.         if (pfs_debug)
  402.           fprintf(stderr, "dirsrv: Can't resolve host %s\n",hostname);
  403. #endif
  404.         perrno = DIRSEND_BAD_HOSTNAME;
  405.         ptlfree(pkt);
  406.         /* return(NULL); */
  407.         return(-1);
  408.         }
  409.         bzero((char *)&to, S_AD_SZ);
  410.         to.sin_family = AF_INET;
  411.         bcopy((char *) &newhostaddr, (char *)&to.sin_addr, 4);
  412.         if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  413.     }
  414.     else {
  415.         pfs_enable = tmp;
  416.         bzero((char *)&to, S_AD_SZ);
  417.         to.sin_family = host->h_addrtype;
  418. #ifdef CUTCP
  419.         bcopy((char *) &host->h_addr, (char *)&to.sin_addr, host->h_length);
  420. #else
  421.         bcopy(host->h_addr, (char *)&to.sin_addr, host->h_length);
  422. #endif
  423.         if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  424.     }
  425.     }
  426.     else bcopy(hostaddr,&to, S_AD_SZ);
  427.     /* lmjm: Save away the hostname */
  428.     strncpy(to_hostname,inet_ntoa(to.sin_addr),sizeof(to_hostname)-1);
  429.  
  430.     if(req_udp_port) to.sin_port = htons(req_udp_port);
  431.     else to.sin_port = dir_udp_port;
  432.  
  433.     /* If a port was specified in hostaddr, use it, otherwise fill it in */
  434.     if(hostaddr) {
  435.     if(hostaddr->sin_port) to.sin_port = hostaddr->sin_port;
  436.     else hostaddr->sin_port = to.sin_port;
  437.     }
  438.  
  439. #ifndef CUTCP
  440.     /* Must open a new port each time. we do not want to see old */
  441.     /* responses to messages we are done with                    */
  442.     if ((lp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  443. #ifdef DEBUG
  444.         if (pfs_debug)
  445.             fprintf(stderr,"dirsrv: Can't open socket\n");
  446. #endif
  447.     perrno = DIRSEND_UDP_CANT;
  448.     ptlfree(pkt);
  449.         /* return(NULL); */
  450.     return(-1);
  451.     }
  452. #endif /* not CUTCP */
  453.  
  454.     /* Try to bind it to a privileged port - loop through candidate */
  455.     /* ports trying to bind.  If failed, that's OK, we will let the */
  456.     /* system assign a non-privileged port later                    */
  457. #ifndef CUTCP
  458.     if(!notprived) {
  459.     for(tmp = PROS_FIRST_PRIVP; tmp < PROS_FIRST_PRIVP+PROS_NUM_PRIVP; 
  460.         tmp++) {
  461. #endif
  462.         bzero((char *)&us, sizeof(us));
  463.         us.sin_family = AF_INET;
  464. #ifndef CUTCP
  465.         us.sin_port = htons((u_short) tmp);
  466.         if (bind(lp, (struct sockaddr *)&us, sizeof(us))) {
  467.         if(errno != EADDRINUSE) {
  468.             notprived++;
  469.             break;
  470.         }
  471.         }
  472.         else break;
  473.     }
  474.     }
  475. #else
  476.     us.sin_port = htons(PROS_FIRST_PRIVP);
  477.     netulisten(PROS_FIRST_PRIVP);
  478. #endif
  479.  
  480. #ifndef USE_V3_PROT
  481.     /* Add header */
  482.     if(rdgram_priority) {
  483.     pkt->start -= 15;
  484.     pkt->length += 15;
  485.     *(pkt->start) = (char) 15;
  486.     bzero(pkt->start+9,4);
  487.     *(pkt->start+11) = 0x02;
  488.     bcopy(&priority,pkt->start+13,2);
  489.     }
  490.     else {
  491.     pkt->start -= 9;
  492.     pkt->length += 9;
  493.     *(pkt->start) = (char) 9;
  494.     }
  495.     this_conn_id = htons(next_conn_id++);
  496.     if(next_conn_id == 0) next_conn_id++;
  497.     bcopy(&this_conn_id,pkt->start+1,2);
  498.     bcopy(&one,pkt->start+3,2);
  499.     bcopy(&one,pkt->start+5,2);
  500.     bzero(pkt->start+7,2);
  501. #endif
  502.  
  503. #ifdef DEBUG
  504.     if (pfs_debug > 2) {
  505. #ifndef USE_V3_PROT
  506.         if (to.sin_family == AF_INET) {
  507.         if(req_udp_port) 
  508.         fprintf(stderr,"Sending message to %s+%d(%d)...",
  509.             to_hostname, req_udp_port, ntohs(this_conn_id));
  510.         else fprintf(stderr,"Sending message to %s(%d)...",
  511.              to_hostname, ntohs(this_conn_id));
  512.     }
  513. #else
  514.         if (to.sin_family == AF_INET) 
  515.         fprintf(stderr,"Sending message to %s...", to_hostname);
  516. #endif /* USE_V3_PROT */
  517.         else
  518.             fprintf(stderr,"Sending message...");
  519.         (void) fflush(stderr);
  520.     }
  521. #endif /* DEBUG */
  522.  
  523.     first = ptalloc();
  524.     next = first;
  525.  
  526. #if defined(XARCHIE) || defined(VARCHIE)
  527.     status2("Connecting to %s (%s)",to_hostname,hostname);
  528.     packetCounter = 0;
  529. #endif
  530.  
  531. #ifndef CUTCP
  532.     return(lp);
  533. #else
  534.     return(1);
  535. #endif /* CUTCP */
  536. }
  537.  
  538. /*    -    -    -    -    -    -    -    -    */
  539. /*
  540.  * This used to be a label to goto to retry the last packet. Now we resend
  541.  * the packet and call keepWaitingDirsend() to wait for a reply. (We
  542.  * call keepWaitingDirsend() because formerly the code dropped through
  543.  * the keep_waiting label.)
  544.  */
  545. static void
  546. retryDirsend()
  547. {
  548. #ifdef CUTCP
  549.     int lretry = 3;
  550. #endif
  551.     gaps = ackpend = 0;
  552.  
  553. #ifndef CUTCP
  554.     ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  555. #else
  556.     while(--lretry) {
  557.         ns = netusend(&to.sin_addr,ntohs(to.sin_port),ntohs(us.sin_port),
  558.               (char *) pkt->start, pkt->length);
  559.         if(!ns)
  560.         break;
  561.         Stask();
  562.         Stask();
  563.         Stask();
  564.     }
  565. #endif /* CUTCP */
  566.  
  567. #ifndef CUTCP
  568.     if(ns != pkt->length) {
  569. #else
  570.     if(ns != 0) {
  571. #endif
  572. #ifdef DEBUG
  573.     if (pfs_debug) {
  574.     fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  575.         perror("");
  576.     }
  577. #endif
  578.     close(lp);
  579.     perrno = DIRSEND_NOT_ALL_SENT;
  580.     ptlfree(first);
  581.     ptlfree(pkt);
  582.     /* return(NULL); */
  583.     dirsendReturn = NULL;
  584.     dirsendDone = DSRET_SEND_ERROR;
  585.     }
  586. #ifdef DEBUG
  587.     if (pfs_debug > 2) fprintf(stderr,"Sent.\n");
  588. #endif
  589.     keepWaitingDirsend();
  590. }
  591.  
  592. /*    -    -    -    -    -    -    -    -    */
  593. /*
  594.  * This used to be a label to goto to set the appropriate timeout value
  595.  * and blocked in select(). Now we set selwait and the fd_sets to the
  596.  * appropriate values, and in X register a new timeout, then return to
  597.  * allow event processing.
  598.  */
  599. static void
  600. keepWaitingDirsend()
  601. {
  602.     /* We come back to this point (by a goto) if the packet */
  603.     /* received is only part of the response, or if the     */
  604.     /* response came from the wrong host            */
  605.  
  606. #ifdef DEBUG
  607.     if (pfs_debug > 2) fprintf(stderr,"Waiting for reply...");
  608. #endif
  609.  
  610. #ifndef CUTCP
  611.     FD_ZERO(&readfds);
  612.     FD_SET(lp, &readfds);
  613. #endif
  614.  
  615.     if(ackpend) selwait = &ackwait;
  616.     else if(gaps) selwait = &gapwait;
  617.     else selwait = &timeout;
  618.  
  619.     addTimeOut();
  620. }
  621.  
  622. /*    -    -    -    -    -    -    -    -    */
  623. /*
  624.  * This routine is called when a timeout occurs. It includes the code that
  625.  * was formerly used when select() returned 0 (indicating a timeout).
  626.  */
  627. /*ARGSUSED*/
  628. static void
  629. timeoutProc(client_data,id)
  630. XtPointer client_data;
  631. XtIntervalId *id;
  632. {
  633.     if (gaps || ackpend) { /* Send acknowledgment */
  634.     /* Acks are piggybacked on retries - If we have received */
  635.     /* an ack from the server, then the packet sent is only  */
  636.     /* an ack and the rest of the message will be empty      */
  637. #ifdef DEBUG
  638.     if (pfs_debug > 2) {
  639.             fprintf(stderr,"Acknowledging (%s).\n",
  640.             (ackpend ? "requested" : "gaps"));
  641.     }    
  642. #endif
  643.     retryDirsend();
  644.     return;
  645.     }
  646.  
  647.     if (retries-- > 0) {
  648.     timeout.tv_sec = CLIENT_DIRSRV_BACKOFF(timeout.tv_sec);
  649. #ifdef DEBUG
  650.     if (pfs_debug > 2) {
  651.             fprintf(stderr,"Timed out.  Setting timeout to %d seconds.\n",
  652.             timeout.tv_sec);
  653.     }
  654. #endif
  655. #if defined(XARCHIE) || defined(VARCHIE)
  656.         status1("Timed out -- retrying (%d seconds)",timeout.tv_sec);
  657. #endif
  658.     retryDirsend();
  659.     return;
  660.     }
  661.  
  662. #ifdef DEBUG
  663.     if (pfs_debug) {
  664.     fprintf(stderr, "select failed(timeoutProc): readfds=%x ",
  665.         readfds);
  666.     perror("");
  667.     }
  668. #endif
  669. #ifndef CUTCP
  670.     close(lp);
  671. #endif
  672.     perrno = DIRSEND_SELECT_FAILED;
  673.     ptlfree(first);
  674.     ptlfree(pkt);
  675.     /* return(NULL); */
  676.     dirsendReturn = NULL;
  677.     dirsendDone = DSRET_TIMEOUT;
  678. }
  679.  
  680. /*    -    -    -    -    -    -    -    -    */
  681. /*
  682.  * This function is called whenever there's something to read on the
  683.  * connection. It includes the code that was run when select() returned
  684.  * greater than 0 (indicating read ready).
  685.  */
  686. /*ARGSUSED*/
  687. static void
  688. readProc(client_data,source,id)
  689. XtPointer client_data;
  690. int *source;
  691. XtInputId *id;
  692. {
  693. #ifdef CUTCP
  694.     int lretry = 3;
  695. #endif
  696.  
  697.     /* We got something to read, so clear the timer */
  698.     removeTimeOut();
  699.  
  700.     from_sz = sizeof(from);
  701.     next->start = next->dat;
  702.  
  703. #ifndef CUTCP
  704.     if ((nr = recvfrom(lp, next->start, sizeof(next->dat), 0, (struct sockaddr *)&from, &from_sz)) < 0) {
  705. #else
  706.     nr = neturead(next->start);
  707.     if (nr < 1) {
  708. #endif
  709. #ifdef DEBUG
  710.         if (pfs_debug) perror("recvfrom");
  711. #endif
  712. #ifndef CUTCP
  713.     close(lp);
  714. #endif
  715.     perrno = DIRSEND_BAD_RECV;
  716.     ptlfree(first);
  717.     ptlfree(pkt);
  718.     /* return(NULL) */
  719.     dirsendReturn = NULL;
  720.     dirsendDone = DSRET_RECV_ERROR;
  721.         return;
  722.     }
  723.  
  724.     next->length = nr;
  725.     next->start[next->length] = 0;
  726.  
  727. #ifdef DEBUG
  728.     if (pfs_debug > 2)
  729.         fprintf(stderr,"Received packet from %s\n",inet_ntoa(from.sin_addr));
  730. #endif
  731.  
  732. #if defined(XARCHIE) || defined(VARCHIE)
  733.     if (packetCounter == 0)
  734.     status2("Connected to %s (%s)",to_hostname,hostname);
  735.     else
  736.     status1("Receiving...%d",packetCounter);
  737.     packetCounter += 1;
  738. #endif
  739.  
  740.     /* For the current format, if the first byte is less than             */
  741.     /* 20, then the first two bits are a version number and the next six  */
  742.     /* are the header length (including the first byte).                  */
  743.     if((hdr_len = (unsigned char) *(next->start)) < 20) {
  744.     ctlptr = next->start + 1;
  745.     next->seq = 0;
  746.     if(hdr_len >= 3) {     /* Connection ID */
  747.         bcopy(ctlptr,&stmp,2);
  748.         if(stmp) pkt_cid = ntohs(stmp);
  749.         ctlptr += 2;
  750.     }
  751.     /*
  752.      * Problem noted by eanders+@cmu.edu against the V5 Prospero server:
  753.      * "the problem is that clients look at a unsigned short as a signed
  754.      * integer.  Then they do comparisons, and naturally they are not
  755.      * equal." This fix is as opposed to some kind of casting, and
  756.      * will be moot when the new clients are written for the new servers.
  757.      */
  758.     if (pkt_cid < 0)
  759.         pkt_cid = 65536+pkt_cid;
  760.     if(pkt_cid && this_conn_id && (pkt_cid != ntohs(this_conn_id))) {
  761.         /* The packet is not for us */
  762.         /* goto keep_waiting; */
  763. #ifdef DEBUG
  764.         if (pfs_debug > 20)
  765.         fprintf(stderr,"Packet not for us %d,%d,%d\n",
  766.             pkt_cid,this_conn_id,ntohs(this_conn_id));
  767. #endif
  768.         keepWaitingDirsend();
  769.         return;
  770.     }
  771.     if(hdr_len >= 5) {    /* Packet number */
  772.         bcopy(ctlptr,&stmp,2);
  773.         next->seq = ntohs(stmp);
  774.         ctlptr += 2;
  775.     }
  776.     else { /* No packet number specified, so this is the only one */
  777.         next->seq = 1;
  778.         nd_pkts = 1;
  779.     }
  780.     if(hdr_len >= 7) {        /* Total number of packets */
  781.         bcopy(ctlptr,&stmp,2);  /* 0 means don't know      */
  782.         if(stmp) nd_pkts = ntohs(stmp);
  783.         ctlptr += 2;
  784.     }
  785.     if(hdr_len >= 9) {    /* Receievd through */
  786.         bcopy(ctlptr,&stmp,2);  /* 1 means received request */
  787. #ifndef USE_V3_PROT
  788.         if((stmp) && (ntohs(stmp) == 1)) {
  789.         /* Future retries will be acks only */
  790.         pkt->length = 9;
  791.         bcopy(&zero,pkt->start+3,2);
  792. #ifdef DEBUG
  793.         if(pfs_debug > 2) 
  794.             fprintf(stderr,"Server acked request - retries will be acks only\n");
  795. #endif
  796.         }
  797. #endif
  798.         ctlptr += 2;
  799.     }
  800.     if(hdr_len >= 11) {    /* Backoff */
  801.         bcopy(ctlptr,&stmp,2);
  802.         if(stmp) {
  803.         backoff = (short)ntohs(stmp);
  804. #ifdef DEBUG
  805.         if(pfs_debug > 2) 
  806.             fprintf(stderr,"Backing off to %d seconds\n", backoff);
  807. #endif
  808.         timeout.tv_sec = backoff;
  809.         if ((backoff > 60) && (first == next) && (no_pkts == 0)) {
  810.             /* Probably a long queue on the server - don't give up */
  811.             retries = client_dirsrv_retry;
  812.         }
  813.         }
  814.         ctlptr += 2;
  815.     }
  816.     if(hdr_len >= 12) {    /* Flags (1st byte) */
  817.         bcopy(ctlptr,&rdflag11,1);
  818.         if(rdflag11 & 0x80) {
  819. #ifdef DEBUG
  820.         if(pfs_debug > 2) 
  821.             fprintf(stderr,"Ack requested\n");
  822. #endif
  823.         ackpend++;
  824.         }
  825.         if(rdflag11 & 0x40) {
  826. #ifdef DEBUG
  827.         if(pfs_debug > 2) 
  828.             fprintf(stderr,"Sequenced control packet\n");
  829. #endif
  830.         next->length = -1;
  831.         scpflag++;
  832.         }
  833.         ctlptr += 1;
  834.     }
  835.     if(hdr_len >= 13) {    /* Flags (2nd byte) */
  836.         /* Reserved for future use */
  837.         bcopy(ctlptr,&rdflag12,1);
  838.         ctlptr += 1;
  839.     }
  840.     if(next->seq == 0) {
  841.         /* goto keep_waiting; */
  842.         keepWaitingDirsend();
  843.         return;
  844.     }
  845.     if(next->length >= 0) next->length -= hdr_len;
  846.     next->start += hdr_len;
  847.     goto done_old;
  848.     }
  849.  
  850.     pkt_cid = 0;
  851.  
  852.     /* if intermediate format (between old and new), then process */
  853.     /* and go to done_old                                         */
  854.     ctlptr = next->start + max(0,next->length-20);
  855.     while(*ctlptr) ctlptr++;
  856.     /* Control fields start after the terminating null */
  857.     ctlptr++;
  858.     /* Until old version are gone, must be 4 extra bytes minimum */
  859.     /* When no version 3 servers, can remove the -4              */
  860.     if(ctlptr < (next->start + next->length - 4)) {
  861.     /* Connection ID */
  862.     bcopy(ctlptr,&stmp,2);
  863.     if(stmp) pkt_cid = ntohs(stmp);
  864.     ctlptr += 2;
  865.     if(pkt_cid && this_conn_id && (pkt_cid != ntohs(this_conn_id))) {
  866.         /* The packet is not for us */
  867.         /* goto keep_waiting; */
  868.         keepWaitingDirsend();
  869.         return;
  870.     }
  871.     /* Packet number */
  872.     if(ctlptr < (next->start + next->length)) {
  873.         bcopy(ctlptr,&stmp,2);
  874.         next->seq = ntohs(stmp);
  875.         ctlptr += 2;
  876.     }
  877.     /* Total number of packets */
  878.     if(ctlptr < (next->start + next->length)) {
  879.         bcopy(ctlptr,&stmp,2);
  880.         if(stmp) nd_pkts = ntohs(stmp);
  881.         ctlptr += 2;
  882.     }
  883.     /* Receievd through */
  884.     if(ctlptr < (next->start + next->length)) {
  885.         /* Not supported by clients */
  886.         ctlptr += 2;
  887.     }
  888.     /* Backoff */
  889.     if(ctlptr < (next->start + next->length)) {
  890.         bcopy(ctlptr,&stmp,2);
  891.         backoff = ntohs(stmp);
  892. #ifdef DEBUG
  893.         if(pfs_debug > 2) 
  894.         fprintf(stderr,"Backing off to %d seconds\n", backoff);
  895. #endif
  896.         if(backoff) timeout.tv_sec = backoff;
  897.         ctlptr += 2;
  898.     }
  899.     if(next->seq == 0) {
  900.         /* goto keep_waiting; */
  901.         keepWaitingDirsend();
  902.         return;
  903.     }
  904.     goto done_old;
  905.  
  906.     }
  907.  
  908.     /* Notes that we have to start searching 11 bytes before the    */
  909.     /* expected start of the MULTI-PACKET line because the message  */
  910.     /* might include up to 10 bytes of data after the trailing null */
  911.     /* The order of those bytes is two bytes each for Connection ID */
  912.     /* Packet-no, of, Received-through, Backoff                     */
  913.     seqtxt = nlsindex(next->start + max(0,next->length - 40),"MULTI-PACKET"); 
  914.     if(seqtxt) seqtxt+= 13;
  915.  
  916.     if((nd_pkts == 0) && (no_pkts == 0) && (seqtxt == NULL)) goto all_done;
  917.  
  918.     tmp = sscanf(seqtxt,"%d OF %d", &(next->seq), &nd_pkts);
  919. #ifdef DEBUG    
  920.     if (pfs_debug && (tmp == 0)) 
  921.     fprintf(stderr,"Cant read packet sequence number: %s", seqtxt);    
  922. #endif
  923.  done_old:
  924. #ifdef DEBUG
  925.     if(pfs_debug > 2) fprintf(stderr,"Packet %d of %d\n",next->seq,nd_pkts);
  926. #endif
  927.     if ((first == next) && (no_pkts == 0)) {
  928.     if(first->seq == 1) {
  929.         comp_thru = first;
  930.         /* If only one packet, then return it */
  931.         if(nd_pkts == 1) goto all_done;
  932.     }
  933.     else gaps++;
  934.     no_pkts = 1;
  935.     next = ptalloc();
  936.     /* goto keep_waiting; */
  937.     keepWaitingDirsend();
  938.     return;
  939.     }
  940.     
  941.     if(comp_thru && (next->seq <= comp_thru->seq))
  942.     ptfree(next);
  943.     else if (next->seq < first->seq) {
  944.     vtmp = first;
  945.     first = next;
  946.     first->next = vtmp;
  947.     first->previous = NULL;
  948.     vtmp->previous = first;
  949.     if(first->seq == 1) comp_thru = first;
  950.     no_pkts++;
  951.     }
  952.     else {
  953.     vtmp = (comp_thru ? comp_thru : first);
  954.     while (vtmp->seq < next->seq) {
  955.         if(vtmp->next == NULL) {
  956.         vtmp->next = next;
  957.         next->previous = vtmp;
  958.         next->next = NULL;
  959.         no_pkts++;
  960.         goto ins_done;
  961.         }
  962.         vtmp = vtmp->next;
  963.     }
  964.     if(vtmp->seq == next->seq)
  965.         ptfree(next);
  966.     else {
  967.         vtmp->previous->next = next;
  968.         next->previous = vtmp->previous;
  969.         next->next = vtmp;
  970.         vtmp->previous = next;
  971.         no_pkts++;
  972.     }
  973.     }   
  974.  
  975. ins_done:
  976.     
  977.     while(comp_thru && comp_thru->next && 
  978.       (comp_thru->next->seq == (comp_thru->seq + 1))) {
  979.     comp_thru = comp_thru->next;
  980. #ifndef USE_V3_PROT
  981.     recvd_thru = htons(comp_thru->seq);
  982.     bcopy(&recvd_thru,pkt->start+7,2); /* Let server know we got it */
  983. #endif
  984.     /* We've made progress, so reset retry count */
  985.     retries = client_dirsrv_retry;
  986.     /* Also, next retry will be only an acknowledgement */
  987.     /* but for now, we can't fill in the ack field      */
  988. #ifdef DEBUG
  989.     if(pfs_debug > 2) 
  990.         fprintf(stderr,"Packets now received through %d\n",comp_thru->seq);
  991. #endif
  992.     }
  993.  
  994.     /* See if there are any gaps */
  995.     if(!comp_thru || comp_thru->next) gaps++;
  996.     else gaps = 0;
  997.  
  998.     if ((nd_pkts == 0) || (no_pkts < nd_pkts)) {
  999.     next = ptalloc();
  1000.     /* goto keep_waiting; */
  1001.     keepWaitingDirsend();
  1002.     return;
  1003.     }
  1004.  
  1005.  all_done:
  1006.     if(ackpend) { /* Send acknowledgement if requested */
  1007. #ifdef DEBUG
  1008.     if (pfs_debug > 2) {
  1009.         if (to.sin_family == AF_INET)
  1010.         fprintf(stderr,"Acknowledging final packet to %s(%d)\n",
  1011.             to_hostname, ntohs(this_conn_id));
  1012.             else
  1013.                 fprintf(stderr,"Acknowledging final packet\n");
  1014.         (void) fflush(stderr);
  1015.     }
  1016. #endif
  1017. #ifndef CUTCP
  1018.     ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  1019. #else
  1020.     while(--lretry) {
  1021.         ns = netusend(&to.sin_addr, ntohs(to.sin_port), ntohs(us.sin_port),(char *) pkt->start, pkt->length);
  1022.         if(!ns)
  1023.             break;
  1024.         Stask();
  1025.         Stask();
  1026.     }
  1027. #endif
  1028.  
  1029. #ifndef CUTCP
  1030.     if(ns != pkt->length) {
  1031. #else
  1032.     if(ns != 0) {
  1033. #endif
  1034.  
  1035. #ifdef DEBUG
  1036.         if (pfs_debug) {
  1037.         fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  1038.         perror("");
  1039.         }
  1040. #endif
  1041.     }
  1042.  
  1043.     }
  1044. #ifndef CUTCP
  1045.     close(lp);
  1046. #endif
  1047.     ptlfree(pkt);
  1048.  
  1049.     /* Get rid of any sequenced control packets */
  1050.     if(scpflag) {
  1051.     while(first && (first->length < 0)) {
  1052.         vtmp = first;
  1053.         first = first->next;
  1054.         if(first) first->previous = NULL;
  1055.         ptfree(vtmp);
  1056.     }
  1057.     vtmp = first;
  1058.     while(vtmp && vtmp->next) {
  1059.         if(vtmp->next->length < 0) {
  1060.         if(vtmp->next->next) {
  1061.             vtmp->next = vtmp->next->next;
  1062.             ptfree(vtmp->next->previous);
  1063.             vtmp->next->previous = vtmp;
  1064.         }
  1065.         else {
  1066.             ptfree(vtmp->next);
  1067.             vtmp->next = NULL;
  1068.         }
  1069.         }
  1070.         vtmp = vtmp->next;
  1071.     }
  1072.     }
  1073.  
  1074.     /* return(first); */
  1075.     dirsendReturn = first;
  1076.     dirsendDone = DSRET_DONE;
  1077.  
  1078. }
  1079. /*    -    -    -    -    -    -    -    -    */
  1080. /* These routines allow dirsend() to run with or without X by providing
  1081.  * wrappers around the calls that handle the asynchronous communication.
  1082.  * All parameters are passed using globals.
  1083.  * Under X: The input sources and timeouts are set using Xt calls, and
  1084.  *        processEvent() just calls XtAppProcessEvent().
  1085.  * Non-X: None of the input sources and timeouts are used, and
  1086.  *      processEvent() calls select() to handle both timeouts and the
  1087.  *      socket file descriptor. The return value of select() is used
  1088.  *      to determine which callback routine to call.
  1089.  */
  1090.  
  1091. static void
  1092. addInputSource()
  1093. {
  1094. #ifdef XARCHIE
  1095.     inputId = XtAppAddInput(appContext,lp,(XtPointer)XtInputReadMask,
  1096.                 readProc,NULL);
  1097. #endif
  1098. }
  1099.  
  1100. static void
  1101. removeInputSource()
  1102. {
  1103. #ifdef XARCHIE
  1104.     XtRemoveInput(inputId);
  1105. #endif
  1106. }
  1107.  
  1108. static void
  1109. addTimeOut()
  1110. {
  1111. #ifdef XARCHIE
  1112.     unsigned long timeoutLen = selwait->tv_sec*1000 + selwait->tv_usec/1000;
  1113.  
  1114.     /* old timeout can still be there if we are being called after the
  1115.      * file descriptor was read, so we remove it just to be sure. */
  1116.     removeTimeOut();
  1117.     timerId = XtAppAddTimeOut(appContext,timeoutLen,timeoutProc,NULL);
  1118. #endif
  1119. }
  1120.  
  1121. static void
  1122. removeTimeOut()
  1123. {
  1124. #ifdef XARCHIE
  1125.     if (timerId != (XtIntervalId)0) {
  1126.     XtRemoveTimeOut(timerId);
  1127.     timerId = (XtIntervalId)0;
  1128.     }
  1129. #endif
  1130. }
  1131.  
  1132. /*
  1133.  * In X, this just calls the X routine that blocks waiting for an event,
  1134.  * timer, or input source and dispatches it.
  1135.  *
  1136.  * Otherwise, for Unix we call select() with the appropriate arguments,
  1137.  * and act on its return calue as follows:
  1138.  *  == 0 : The timer expired, call timeoutProc() then return to, presumably,
  1139.  *         the loop that calling processEvent() until dirsendDone.
  1140.  *  < 0 :  If we were interrupted (errno == EINTR) then don't do anything.
  1141.  *         Presumably the signal handler set flags if needed, and we'll
  1142.  *         come back to select() again on the next pass of the outer loop
  1143.  *         if we're supposed to. Otherwise, puke on the error.
  1144.  *  > 0 :  The socket is ready for reading, so call readProc().
  1145.  *
  1146.  * Otherwise, if we're in MSDOS (CUTCP defined) then I (gf) have no idea
  1147.  * what's going on. Ask Brendan.
  1148.  */
  1149. static void
  1150. processEvent()
  1151. {
  1152. #ifdef CUTCP
  1153.     unsigned long now;
  1154. #endif
  1155. #ifdef XARCHIE
  1156.     XtAppProcessEvent(appContext,XtIMAll);
  1157. #else
  1158.     /* select - either recv is ready, or timeout */
  1159.     /* see if timeout or error or wrong descriptor */
  1160. #ifndef CUTCP
  1161.     tmp = select(lp + 1, &readfds, (fd_set *)0, (fd_set *)0, selwait);
  1162.     if (tmp == 0) {
  1163.     timeoutProc(NULL,&timerId);
  1164.     } else if (tmp < 0 && errno == EINTR) {    /* gf: new for ^C in varchie */
  1165. #ifdef DEBUG
  1166.     fprintf(stderr,"select interrupted\n");    /* do nothing, we'll be back */
  1167. #endif
  1168.     } else if ((tmp < 0) || !FD_ISSET(lp,&readfds)) {
  1169. #ifdef DEBUG
  1170.     if (pfs_debug) {
  1171.         fprintf(stderr, "select failed(processEvent): readfds=%x ",
  1172.             readfds);
  1173.         perror("");
  1174.     }
  1175. #endif
  1176.     close(lp);
  1177. #else /* CUTCP's flood. */
  1178.     /* while not timeout in selwait loop, stask looking for uevents */
  1179.     now = time(NULL) + selwait->tv_sec;
  1180. #ifdef    DEBUG
  1181.     if(pfs_debug) {
  1182.         fprintf(stderr,"Waiting %d seconds\n",selwait->tv_sec);
  1183.     }
  1184.  
  1185. #endif
  1186.     while(now > time(NULL)) {
  1187.         int    i, cl, dat;
  1188.  
  1189.         Stask();
  1190.         if (0 < (i = Sgetevent(USERCLASS, &cl, &dat))) {
  1191.             /* got a user class event */
  1192.             if(cl == USERCLASS &&
  1193.                 i == UDPDATA) {
  1194.                     readProc(NULL,&lp,&inputId);
  1195.                     return;
  1196.             }
  1197.         }
  1198.         if(kbhit()) {
  1199.             int c = getch();
  1200.             if(c == 27 || c == 3)
  1201.                 break;
  1202.             fprintf(stderr,"Press <ESCAPE> to abort\n");
  1203.         }
  1204.     }
  1205.     if(now <= time(NULL)) { /* timeout */
  1206.         timeoutProc(NULL,&timerId);
  1207.          return;
  1208.     }
  1209.  
  1210. #endif /* CUTCP */
  1211.     perrno = DIRSEND_SELECT_FAILED;
  1212.     ptlfree(first);
  1213.     ptlfree(pkt);
  1214.     /* return(NULL); */
  1215.     dirsendReturn = NULL;
  1216.     dirsendDone = DSRET_SELECT_ERROR;
  1217. #ifndef CUTCP
  1218.     } else {
  1219.     readProc(NULL,&lp,&inputId);
  1220.     }
  1221. #endif /* CUTCP */
  1222. #endif /* XARCHIE */
  1223. }
  1224.  
  1225. void
  1226. abortDirsend()
  1227. {
  1228.     if (!dirsendDone) {
  1229. #ifndef CUTCP
  1230.     close(lp);
  1231. #endif
  1232.     ptlfree(first);
  1233.     ptlfree(pkt);
  1234.     dirsendReturn = NULL;
  1235.     dirsendDone = DSRET_ABORTED;
  1236.     }
  1237.     return;
  1238. }
  1239.